// --- Copyright (c) 2006-2008 Stefan Kyntchev ---
// This software is written and copyrighted by Stefan Kyntchev 
// and BeyondPod Team members. All rights are reserved.
// Author contact: support@beyondpod.mobi
// ------------------------------------------------------------------------
// This file is part of BeyondPod RSS Feed Reader and Podcast manager
// (www.codeplex.com/BeyondPod) 
// BeyondPod is free software: you can redistribute it and/or modify 
// it under the terms of the GNU General Public License as published by 
// the Free Software Foundation, either version 3 of the License, or 
// (at your option) any later version. 
//  
// BeyondPod is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
// GNU General Public License for more details. 
//  
// You should have received a copy of the GNU General Public License
// along with BeyondPod. If not, see <http://www.gnu.org/licenses/>
// ------------------------------------------------------------------------
// COPYRIGHT NOTICE: This copyright notice may NOT be removed, obscured or modified 
// without written consent from the author.
// --- End copyright notice --- 


using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using svs.Mobile.BeyondMedia.FeedCore;
using svs.Mobile.BeyondMedia.FeedCore.Helpers;
using svs.Mobile.BeyondMedia.Forms;
using svs.Mobile.BeyondMedia.Objects;
using svs.Mobile.BeyondMedia.UiCore.GDI;
using svs.Mobile.BeyondMedia.UiCore.KineticControls;

namespace svs.Mobile.BeyondMedia.Controls
{
	/// <summary>
	/// Provide a 2 line listview
	/// </summary>
	internal class KineticTracksView : KineticListView, IView, ITracksView
	{
		private Point m_AnimationFrame;
		private Feed m_FeedFilter;
		readonly TrackList m_Items = new TrackList();
		
		#region Events

		
		public event Helpers.TrackSelectedEvent Select;
		public event Helpers.NavigationEvent Navigation;

		#endregion

		#region Constructor

		public KineticTracksView()
		{
			FeedRepository.TrackDeleted += OnTrackDeleted;
			FeedRepository.TrackAdded += OnTrackAdded;
		}

		public TrackList Items
		{
			get
			{
				return m_Items;
			}
		}

		#endregion

		#region Private Methods

		protected virtual void OnTrackAdded(Track i_track)
		{
			if (InvokeRequired)
			{
				TrackUpdatedDelegate cbDel = OnTrackAdded;
				Invoke(cbDel, i_track);
				return;
			}

			if (IsAllowed(i_track))
			{
				LoadTracks(SelectedTrack, false);
			}
		}

		private void LoadTracks(Track trackToSelect, bool preserveScrollPosition)
		{
			Items.Clear();

			TrackList tracks = new TrackList();
			tracks.AddRange(FeedRepository.GetAllTracks().FindAll(IsAllowed));

			if (m_FeedFilter == null) // we show all tracks in the category
			{
				if(Configuration.GroupByFeedIfShowingCategoryTracks)
					FeedRepository.SortTrackUsingDefaultSettingsGroupedByFeed(tracks);
				else
					FeedRepository.SortTrackUsingDefaultSettings(tracks);
			}

			Items.AddRange(tracks);

			int selected = trackToSelect != null ? GetItemIndex(trackToSelect) : GetFirstUnplayedTrack();

			ViewManager.TrySetTitle(Title);

			SetItems(BuildNativeControlItems(), selected, preserveScrollPosition);
		}

		private bool IsAllowed(Track track)
		{
			if(track == null ) return false;

			if (m_FeedFilter == null)
				return CategoryManager.IsInActiveCategory(track.ParentFeed);
			
			return track.ParentFeed == m_FeedFilter;
		}

		protected virtual void OnTrackDeleted(Track i_track)
		{
			if (InvokeRequired)
			{
				TrackUpdatedDelegate cbDel = OnTrackDeleted;

				Invoke(cbDel, i_track);
				return;
			}

			if (Items.Contains(i_track))
			{
				int selectedIndex = SelectedIndex;

				Items.Remove(i_track);

				//Deal with the current selection
				if (SelectedTrack == i_track)
				{
					if (Items.Count > 0)
					{
						if (SelectedIndex >= Items.Count)
							SelectedIndex = Items.Count - 1;
					}
					else
						SelectedIndex = -1;
				}

				if(ViewManager.CurrentViewName == Helpers.ViewNames.Tracks)
					ViewManager.TrySetTitle(Title);

				SetItems(BuildNativeControlItems(), selectedIndex, false);
			}
		}

		private int GetFirstUnplayedTrack()
		{
			for (int i = 0; i != Items.Count; i++)
			{
				if ((Items[i]).IsNew || (Items[i]).IsPartialyPlayed)
				{
					return i;
				}
			}

			return -1;
		}

		// Check if the user presses the action key

		private void OnNavigation(Helpers.NavigationDirection i_direction)
		{
			if (Navigation != null)
				Navigation(this, i_direction);
		}

		protected delegate void TrackUpdatedDelegate(Track i_track);

		#endregion

		#region Protected Methods

		protected override void OnKeyDown(KeyEventArgs e)
		{
			switch (e.KeyCode)
			{
				case Keys.Return:

					if (SelectedIndex != -1)
					{
						PlaySelected();
					}
					e.Handled = true;
					break;

					//Left Right
				case Keys.Left:
					OnNavigation(Helpers.NavigationDirection.Back);
					e.Handled = true;
					break;

					//Left Right
				case Keys.Right:
					OnNavigation(Helpers.NavigationDirection.Forward);
					e.Handled = true;
					break;
			}

			if (!e.Handled)
			{
				base.OnKeyDown(e);

				if (!e.Handled)
					e.Handled = ShortcutKeyManager.HandleKey(e.KeyCode);
			}
		}

		protected override void  OnItemBodyClicked(int index)
		{
				PlaySelected();
		}

		#endregion

		#region Public Properties

		/// <summary>
		/// Gets the current playlist.
		/// </summary>
		/// <value>The current playlist.</value>
		public TrackList CurrentPlaylist
		{
			get
			{
				TrackList retVal = new TrackList();
				for (int i = 0; i != Items.Count; i++)
				{
					retVal.Add(Items[i]);
				}
				return retVal;
			}
		}

		public Track SelectedTrack
		{
			get
			{
				if (SelectedIndex >= 0 && SelectedIndex < Items.Count)
					return Items[SelectedIndex];

				return null;
			}

			set
			{
				SelectedIndex = Items.IndexOf(value);
				ScrollItemIntoView(SelectedIndex);
			}
		}

		/// <summary>
		/// Gets the title.
		/// </summary>
		/// <value>The title.</value>
		public string Title
		{
			get
			{
					return string.Format("Podcasts ({0})", Items.Count);
			}
		}

		/// <summary>
		/// Gets the view menu.
		/// </summary>
		/// <value>The view menu.</value>
		public MainMenu ViewMenu
		{
			get { return MenuManager.GetMenu(Helpers.ViewNames.Tracks); }
		}

		#endregion

		#region Public Methods

		public void Initialize()
		{
			Items.Clear();
			Items.AddRange(FeedRepository.GetAllTracks().FindAll(IsAllowed));
		}

		public void OnBeforeActivate()
		{
		}

		public void OnAfterDeactivate()
		{
			
		}

		public void OnAfterActivate()
		{
			Focus();
		}

		/// <summary>
		/// Plays the selected.
		/// </summary>
		public void PlaySelected()
		{
			if (SelectedTrack == null)
			{
				Helpers.Beep();
				return;
			}

			if (Select != null)
				Select(SelectedTrack);
		}

		/// <summary>
		/// Clears this instance.
		/// </summary>
		public void Clear()
		{
			m_FeedFilter = null;
			Items.Clear();
			SelectedIndex = -1;
			RefreshList();
		}

		public void Reload()
		{
			if (Master.MasterForm.InvokeRequired)
			{
				Master.MasterForm.Invoke(new ReloadDelegate(Reload));
				return;
			}

			LoadTracks(SelectedTrack, true);
		}

		private delegate void ReloadDelegate();

		/// <summary>
		/// True if the view is showing data for a given feed
		/// </summary>
		/// <param name="feed"></param>
		/// <returns></returns>
		public bool IsShowingFeed(Feed feed)
		{
			return !HasFeedFilter() || m_FeedFilter == feed;
		}

		public void ClearFeedFilter()
		{
			SetFeedFilter(null);
		}

		public Feed GetFeedFilter()
		{
			return m_FeedFilter;
		}

		public void SetFeedFilter(Feed feed)
		{
			if (m_FeedFilter != feed || (m_FeedFilter == null && ItemCount == 0))
			{
				m_FeedFilter = feed;
				LoadTracks(null, false);
			}
		}

		public bool HasFeedFilter()
		{
			return m_FeedFilter != null;
		}

		public void SelectNextTrack()
		{
			if (SelectedIndex < Items.Count - 1)
			{
				SelectedTrack = Items[SelectedIndex + 1];
			}
		}

		public void NotifyTrackStatusChanged(Track track)
		{
			UpdateItem(track, false);
		}

		protected void UpdateItem(Track track, bool scrollIntoView)
		{
			int inx = GetItemIndex(track);

			if (inx != -1)
			{
				UpdateItem(BuiltNativeControlItem(track), inx);

				if(scrollIntoView)
					ScrollItemIntoView(inx);
			}
		}

		#endregion

		protected int GetItemIndex(Track track)
		{
			int index = -1;

			if (Items.Count > 0)
			{
				if (track != null)
				{
					index = Items.IndexOf(track);
				}
			}
			return index;
		}

		protected override void DrawItemBackgroundOn(Gdi g, ListViewItemData item,  Rectangle rItem, int nItem, bool isSelected)
		{
			base.DrawItemBackgroundOn(g, item, rItem, nItem, isSelected);

			if (item.PercentHighlighted > 0)
			{
				float width = rItem.Width;
				width *= item.PercentHighlighted;

				var highlighted = new Rectangle(rItem.Left, rItem.Top, (int) Math.Floor(width), rItem.Height);

				g.GradientFill(highlighted, isSelected ? Settings.ItemHighLightColor1 :
																								Settings.ListItemBackgroundColorOdd,
																		isSelected ? Helpers.ChangeColorIntensity(Settings.ItemHighLightColor1, 0.75) :
																		Helpers.ChangeColorIntensity(nItem % 2 == 0? Settings.ListItemBackgroundColorEven:
																																 Settings.ListItemBackgroundColorOdd, 0.75),
																																	Gdi.FillDirection.LeftToRight);
			}
		}
    
		protected override List<ListViewItemData> BuildNativeControlItems()
		{
			var retVal = new List<ListViewItemData>(m_Items.Count);

			foreach (var feed in m_Items)
			{
				retVal.Add(BuiltNativeControlItem(feed));
			}

			return retVal;
		}

		protected virtual ListViewItemData BuiltNativeControlItem(Track track)
		{
			string group = null;
			
			if(HasFeedFilter() || Configuration.GroupByFeedIfShowingCategoryTracks)
					group = track.ParentFeed.Name;

			var i = new ListViewItemData
			        	{
			        		Group = group,
			        		PrimaryText = track.Name,
			        		PrimaryImage = null,
			        		OverlayImage = null,
			        		SecondaryImage = null,
			        		PercentHighlighted = track.PlayedAsFraction,
			        		LeftTrunkatePrimaryText = track.ParentFeed.LeftTruncateLongTrackNames
			        	};

			// Draw the image
			if (track.DownloadStatus == Track.DownloadStatuses.Downloading || !track.IsFullyDownloaded)
			{
				i.PrimaryImage = FeedImageList.DownloadingTrackImage;
				m_AnimationFrame.Offset(i.PrimaryImage.ViewportSize.Width,0);
				if (m_AnimationFrame.X >= i.PrimaryImage.ImageSize.Width)
					m_AnimationFrame.Offset(-i.PrimaryImage.ImageSize.Width,0);

				i.PrimaryImage.ImageOffset = m_AnimationFrame;
			}
			else
			{
				if (track.CurrentPlayState == Track.PlayMode.Play)
					i.PrimaryImage = FeedImageList.PlayingTrackImage;
				else
				i.PrimaryImage = track.WillUseInternalPlayer
					?  track.IsPlayed ? FeedImageList.PlayedTrackImage : FeedImageList.TrackImage
					:  track.IsPlayed ? FeedImageList.PlayedExternalTrackImage : FeedImageList.ExternalTrackImage;
			}

			if (!track.IsFullyDownloaded)
			{
				if (track.DownloadSize <= 0)
				{
					i.SecondaryText = string.Format("{0} {1}",
																 track.DownloadStatus,
																 CoreHelper.GetFileLengthAsString(track.DownloadedPortion));
				}
				else
				{
					i.SecondaryText = string.Format("{0} {1}% of {2}",
																 track.DownloadStatus,
																 (int)track.DownloadPercent,
																 CoreHelper.GetFileLengthAsString(track.DownloadSize));
				}
			}
			else
			{
				i.SecondaryText = CoreHelper.FormatDate(track.LastModifiedDate);

				if (track.TotalTime > 0)
					i.SecondaryText += ", " + track.TotalTimeAsString;

				if (!track.ParentFeed.CanDeleteTracks)
				{
					i.OverlayImage = FeedImageList.LockedOverlay;
				}
			}

			return i;
		}
	}
}